package cn.kmsoft.common.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 基于java。security库开展文件Hash码生成工作
 */
public class ChecksumUtil {
    private static final String MD5_ALGORITHM = "MD5";
    private static final String SHA256_ALGORITHM = "SHA-256";

    private static String getFileChecksum(MessageDigest digest, File file) throws IOException
    {
        //Get file input stream for reading the file content
        FileInputStream fis = new FileInputStream(file);

        //Create byte array to read data in chunks
        byte[] byteArray = new byte[1024];
        int bytesCount = 0;

        //Read file data and update in message digest
        while ((bytesCount = fis.read(byteArray)) != -1) {
            digest.update(byteArray, 0, bytesCount);
        };

        //close the stream; We don't need it now.
        fis.close();

        //Get the hash's bytes
        byte[] bytes = digest.digest();

        //This bytes[] has bytes in decimal format;
        //Convert it to hexadecimal format
        StringBuilder sb = new StringBuilder();
        for(int i=0; i< bytes.length ;i++)
        {
            sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
        }

        //return complete hash
        return sb.toString();
    }

    public static String getStrChecksumSHA256(String str) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
            byte[] hash = messageDigest.digest(str.getBytes(StandardCharsets.UTF_8));
            StringBuilder stringBuilder = new StringBuilder();
            for (byte b : hash) {
                //stringBuilder.append(String.format("%02x", b));
                stringBuilder.append(Integer.toHexString((b & 0xFF) | 0x100),1,3);
            }
            return stringBuilder.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 以公开的SHA-256算法获取文件Hash序列
     *
     * @param file
     * @return
     */
    public static String getFileChecksumBySHA256(File file){
        if(!file.exists() || !file.isFile()) {
            return "";
        }

        String checksum="";
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            checksum = getFileChecksum(digest,file);
        } catch (NoSuchAlgorithmException | IOException e) {
            e.printStackTrace();
        }

        return checksum;
    }

    /**
     * 以公开的MD5算法获取文件Hash序列
     *
     * @param file
     * @return
     */
    public static String getFileChecksumByMD5(File file){
        if(!file.exists() || !file.isFile()) {
            return "";
        }

        String checksum="";
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            checksum = getFileChecksum(digest,file);
        } catch (NoSuchAlgorithmException | IOException e) {
            e.printStackTrace();
        }

        return checksum;
    }

    public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
        //Create checksum for this file
        String filepath="c:/tmp/2021-10-18-raspbian-buster-full.img";
        String filepath2="C:\\Users\\wangq\\Downloads\\postgresql-12.17.tar.bz2";
        File file = new File(filepath2);

        //Use MD5 algorithm
        String checksumMD5 = ChecksumUtil.getFileChecksumByMD5(file);
        String checksumSHA256 = ChecksumUtil.getFileChecksumBySHA256(file);

        //see checksum
        System.out.println();
        System.out.println(String.format("--->filepath: %s",file.getAbsolutePath()));
        System.out.println(String.format("--->checksumMD5: %s",checksumMD5));
        System.out.println(String.format("--->checksumSHA256: %s",checksumSHA256));
    }
}
